
#ifndef _FUNCTION_BINDER_
#define _FUNCTION_BINDER_

//////////////////////////////////////////////////////////////////////////

namespace nebula { namespace utility {

template<typename proc>
struct proc_binder
{
    proc _proc;

    proc_binder(proc& fn) :
    _proc(fn)
    {}

    void operator()() {
        _proc();
    }
};

template<typename proc, typename p1>
struct proc_binder_1
{
    proc _proc;
    p1   _para1;


    proc_binder_1(proc& fn, p1& _p1) :
        _proc(fn), _para1(_p1)
    {}

    void operator()() {
        _proc(_para1);
    }
};

template<typename proc, typename p1, typename p2>
struct proc_binder_2
{
    proc _proc;

    p1   _para1;
    p2   _para2;

    proc_binder_2(proc& fn, p1& _p1, p2& _p2) :
    _proc(fn), _para1(_p1), _para2(_p2)
    {}

    void operator()() {
        _proc(_para1, _para2);
    }
};

template<typename proc, typename p1, typename p2, typename p3>
struct proc_binder_3
{
    proc _proc;

    p1   _para1;
    p2   _para2;
    p3   _para3;

    proc_binder_3(proc& fn, p1& _p1, p2& _p2, p3& _p3) :
    _proc(fn), _para1(_p1), _para2(_p2), _para3(_p3)
    {}

    void operator()() {
        _proc(_para1, _para2, _para3);
    }
};

template<typename proc, typename p1, typename p2, typename p3, typename p4>
struct proc_binder_4
{
    proc _proc;

    p1   _para1;
    p2   _para2;
    p3   _para3;
    p4   _para4;

    proc_binder_4(proc& fn, p1& _p1, p2& _p2, p3& _p3, p4& _p4) :
    _proc(fn), _para1(_p1), _para2(_p2), _para3(_p3), _para4(_p4)
    {}

    void operator()() {
        _proc(_para1, _para2, _para3, _para4);
    }
};

//////////////////////////////////////////////////////////////////////////

template<typename obj_type, typename ret_type>
struct mem_func_binder
{
    typedef ret_type (obj_type::*func_t)();

    func_t    _func;
    obj_type* _obj;

    mem_func_binder(obj_type* obj, ret_type (obj_type::*func)()) :
        _func(func), _obj(obj)
    {}

    void operator()() {
        (_obj->*_func)();
    }
};

template<typename obj_type, typename ret_type>
mem_func_binder<obj_type, ret_type>
make_mem_func(obj_type* obj, ret_type (obj_type::*func)())
{
    return mem_func_binder<obj_type, ret_type>(obj, func);
}

template<
    typename obj_type, typename ret_type,
    typename p1
>
struct mem_func_binder_1
{
    typedef ret_type (obj_type::*func_t)(p1);

    func_t    _func;
    obj_type* _obj;
    p1        _para1;

    mem_func_binder_1(obj_type* obj, ret_type (obj_type::*func)(p1), p1 _p1) :
        _func(func), _obj(obj), _para1(_p1)
    {}

    void operator()() {
        (_obj->*_func)(_para1);
    }
};

template<typename obj_type, typename ret_type, typename p1>
mem_func_binder_1<obj_type, ret_type, p1>
make_mem_func(obj_type* obj, ret_type (obj_type::*func)(p1), p1 _p1)
{
    return mem_func_binder_1<obj_type, ret_type, p1>(obj, func, _p1);
}

template<typename obj_type, typename ret_type,
    typename p1, typename p2>
struct mem_func_binder_2
{
    typedef ret_type (obj_type::*func_t)(p1, p2);

    func_t    _func;
    obj_type* _obj;
    p1 _para1;
    p2 _para2;

    mem_func_binder_2(
        obj_type* obj, ret_type (obj_type::*func)(p1, p2), p1 _p1, p2 _p2
        ) :
    _func(func), _obj(obj), _para1(_p1), _para2(_p2)
    {}

    void operator()() {
        (_obj->*_func)(_para1, _para2);
    }
};

template<typename obj_type, typename ret_type, typename p1, typename p2>
mem_func_binder_2<obj_type, ret_type, p1, p2>
make_mem_func(obj_type* obj, ret_type (obj_type::*func)(p1, p2), p1 _p1, p2 _p2)
{
    return
        mem_func_binder_2<
            obj_type, ret_type, p1, p2
        >(obj, func, _p1, _p2);
}

}} // namespace nebula::utility

#endif
